
#include <condition_variable>
#include <mutex>
#include <future>
#include <thread>
#include <iostream>
#include <queue>
#include <memory>

template <typename T> class Myqueue 
{
public:
    int push(const T &x)
    {
        {
            std::lock_guard<std::mutex> lg(mut);
            queue.push(x);
        }
        cond.notify_one();
        return 0;
    }

    T get()
    {
        std::unique_lock<std::mutex> ul(mut);
        if (queue.empty())
        {
            cond.wait(ul, [this]{ return !this->queue.empty();});
        }
        T val = queue.front();
        queue.pop();
        return val;
    }

private:
    std::mutex mut;
    std::condition_variable cond;
    std::queue<T> queue;
};


void consumer(std::shared_ptr<Myqueue<int>> q)
{
    while(true)
    {
        int val = q->get();
        std::cout <<"consumer: " << val << std::endl;
    }
}

int main()
{
    // std::shared_ptr<Myqueue<int>>  q(new Myqueue<int>);
    auto q = std::make_shared<Myqueue<int>>();

    for (int i = 0; i < 5; ++ i)
    {
        q->push(i);
    }
    std::this_thread::sleep_for(std::chrono::seconds(2));
    auto c1 = std::async(std::launch::async, consumer, q);
    while(true)
    {
        for (int i = 0; i < 5; ++ i)
        {
            q->push(i);
        }
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}
